"""
文件名: performance.py
描述: 性能监控和优化工具

本模块包含以下主要功能：
1. API响应时间监控
2. 数据库查询性能分析
3. 内存使用监控
4. 慢查询检测和优化建议

依赖模块:
   - time: 时间测量
   - psutil: 系统信息
   - asyncio: 异步支持
   - core: 配置和日志模块

使用示例:
   >>> @monitor_performance
   >>> async def slow_function():
   >>>     await asyncio.sleep(1)

注意事项:
   - 性能监控会增加少量开销
   - 生产环境要控制监控频率
   - 慢查询日志要定期清理
   - 内存监控要考虑容器环境

作者: AI助手
创建日期: 2024-06-27
最后修改: 2024-06-27
版本: 1.0.0
"""

import time
import asyncio
import psutil
from datetime import datetime, timedelta
from functools import wraps
from typing import Dict, List, Any, Optional, Callable
from collections import defaultdict, deque
import statistics

from src.core.logger import get_logger
from src.core.config import get_settings

settings = get_settings()
logger = get_logger(__name__)


class PerformanceMonitor:
    """性能监控器"""
    
    def __init__(self):
        self.api_metrics = defaultdict(list)
        self.db_metrics = defaultdict(list)
        self.system_metrics = deque(maxlen=1000)
        self.slow_queries = deque(maxlen=100)
        self.alert_thresholds = {
            'api_response_time': 5.0,  # 秒
            'db_query_time': 2.0,      # 秒
            'memory_usage': 80.0,       # 百分比
            'cpu_usage': 85.0,          # 百分比
        }
    
    def record_api_metric(self, endpoint: str, method: str, response_time: float, status_code: int):
        """记录API性能指标"""
        metric = {
            'endpoint': endpoint,
            'method': method,
            'response_time': response_time,
            'status_code': status_code,
            'timestamp': datetime.utcnow(),
        }
        
        self.api_metrics[f"{method} {endpoint}"].append(metric)
        
        # 检查是否超过阈值
        if response_time > self.alert_thresholds['api_response_time']:
            logger.warning(f"慢API请求检测", 
                         endpoint=endpoint, 
                         method=method, 
                         response_time=response_time)
    
    def record_db_metric(self, query_type: str, query_time: float, table: str = None):
        """记录数据库性能指标"""
        metric = {
            'query_type': query_type,
            'query_time': query_time,
            'table': table,
            'timestamp': datetime.utcnow(),
        }
        
        self.db_metrics[query_type].append(metric)
        
        # 检查慢查询
        if query_time > self.alert_thresholds['db_query_time']:
            self.slow_queries.append(metric)
            logger.warning(f"慢查询检测", 
                         query_type=query_type, 
                         table=table, 
                         query_time=query_time)
    
    def record_system_metric(self):
        """记录系统性能指标"""
        try:
            cpu_percent = psutil.cpu_percent(interval=None)
            memory = psutil.virtual_memory()
            disk = psutil.disk_usage('/')
            
            metric = {
                'cpu_usage': cpu_percent,
                'memory_usage': memory.percent,
                'memory_available': memory.available,
                'disk_usage': disk.percent,
                'timestamp': datetime.utcnow(),
            }
            
            self.system_metrics.append(metric)
            
            # 检查系统资源告警
            if cpu_percent > self.alert_thresholds['cpu_usage']:
                logger.warning(f"CPU使用率过高", cpu_usage=cpu_percent)
            
            if memory.percent > self.alert_thresholds['memory_usage']:
                logger.warning(f"内存使用率过高", memory_usage=memory.percent)
                
        except Exception as e:
            logger.error(f"系统指标收集失败: {e}")
    
    def get_api_stats(self, endpoint: str = None, hours: int = 24) -> Dict[str, Any]:
        """获取API性能统计"""
        cutoff_time = datetime.utcnow() - timedelta(hours=hours)
        
        if endpoint:
            metrics = self.api_metrics.get(endpoint, [])
        else:
            metrics = []
            for endpoint_metrics in self.api_metrics.values():
                metrics.extend(endpoint_metrics)
        
        # 过滤时间范围
        recent_metrics = [m for m in metrics if m['timestamp'] > cutoff_time]
        
        if not recent_metrics:
            return {"total_requests": 0}
        
        response_times = [m['response_time'] for m in recent_metrics]
        status_codes = [m['status_code'] for m in recent_metrics]
        
        return {
            "total_requests": len(recent_metrics),
            "avg_response_time": statistics.mean(response_times),
            "min_response_time": min(response_times),
            "max_response_time": max(response_times),
            "p95_response_time": statistics.quantiles(response_times, n=20)[18] if len(response_times) > 20 else max(response_times),
            "success_rate": len([c for c in status_codes if 200 <= c < 300]) / len(status_codes) * 100,
            "error_rate": len([c for c in status_codes if c >= 400]) / len(status_codes) * 100,
        }
    
    def get_db_stats(self, hours: int = 24) -> Dict[str, Any]:
        """获取数据库性能统计"""
        cutoff_time = datetime.utcnow() - timedelta(hours=hours)
        
        all_metrics = []
        for query_metrics in self.db_metrics.values():
            all_metrics.extend(query_metrics)
        
        # 过滤时间范围
        recent_metrics = [m for m in all_metrics if m['timestamp'] > cutoff_time]
        
        if not recent_metrics:
            return {"total_queries": 0}
        
        query_times = [m['query_time'] for m in recent_metrics]
        query_types = [m['query_type'] for m in recent_metrics]
        
        # 按查询类型统计
        type_stats = defaultdict(list)
        for metric in recent_metrics:
            type_stats[metric['query_type']].append(metric['query_time'])
        
        type_summary = {}
        for query_type, times in type_stats.items():
            type_summary[query_type] = {
                "count": len(times),
                "avg_time": statistics.mean(times),
                "max_time": max(times),
            }
        
        return {
            "total_queries": len(recent_metrics),
            "avg_query_time": statistics.mean(query_times),
            "max_query_time": max(query_times),
            "slow_queries_count": len([t for t in query_times if t > self.alert_thresholds['db_query_time']]),
            "queries_by_type": type_summary,
        }
    
    def get_system_stats(self, minutes: int = 60) -> Dict[str, Any]:
        """获取系统性能统计"""
        cutoff_time = datetime.utcnow() - timedelta(minutes=minutes)
        
        recent_metrics = [m for m in self.system_metrics if m['timestamp'] > cutoff_time]
        
        if not recent_metrics:
            return {"no_data": True}
        
        cpu_usages = [m['cpu_usage'] for m in recent_metrics]
        memory_usages = [m['memory_usage'] for m in recent_metrics]
        
        return {
            "avg_cpu_usage": statistics.mean(cpu_usages),
            "max_cpu_usage": max(cpu_usages),
            "avg_memory_usage": statistics.mean(memory_usages),
            "max_memory_usage": max(memory_usages),
            "sample_count": len(recent_metrics),
            "current_memory_available": recent_metrics[-1]['memory_available'] if recent_metrics else 0,
        }
    
    def get_slow_queries(self, limit: int = 10) -> List[Dict[str, Any]]:
        """获取最近的慢查询"""
        return list(self.slow_queries)[-limit:]
    
    def generate_performance_report(self) -> Dict[str, Any]:
        """生成性能报告"""
        return {
            "timestamp": datetime.utcnow().isoformat(),
            "api_performance": self.get_api_stats(),
            "database_performance": self.get_db_stats(),
            "system_performance": self.get_system_stats(),
            "slow_queries": self.get_slow_queries(),
            "thresholds": self.alert_thresholds,
        }


# 全局性能监控器实例
performance_monitor = PerformanceMonitor()


def monitor_performance(
    metric_type: str = "api",
    track_memory: bool = False,
    log_slow: bool = True
):
    """
    性能监控装饰器
    
    Args:
        metric_type: 指标类型 (api, db, custom)
        track_memory: 是否跟踪内存使用
        log_slow: 是否记录慢操作
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            start_time = time.time()
            start_memory = psutil.Process().memory_info().rss if track_memory else 0
            
            try:
                result = await func(*args, **kwargs)
                execution_time = time.time() - start_time
                
                # 记录性能指标
                if metric_type == "api":
                    # 从参数中提取endpoint信息
                    endpoint = getattr(func, '__name__', 'unknown')
                    performance_monitor.record_api_metric(
                        endpoint=endpoint,
                        method="ASYNC",
                        response_time=execution_time,
                        status_code=200
                    )
                elif metric_type == "db":
                    performance_monitor.record_db_metric(
                        query_type=func.__name__,
                        query_time=execution_time
                    )
                
                # 记录内存使用
                if track_memory:
                    end_memory = psutil.Process().memory_info().rss
                    memory_delta = end_memory - start_memory
                    if memory_delta > 50 * 1024 * 1024:  # 50MB
                        logger.warning(f"高内存使用检测", 
                                     function=func.__name__, 
                                     memory_delta=memory_delta)
                
                # 记录慢操作
                if log_slow and execution_time > 1.0:
                    logger.info(f"慢操作检测", 
                              function=func.__name__, 
                              execution_time=execution_time)
                
                return result
                
            except Exception as e:
                execution_time = time.time() - start_time
                
                if metric_type == "api":
                    performance_monitor.record_api_metric(
                        endpoint=func.__name__,
                        method="ASYNC",
                        response_time=execution_time,
                        status_code=500
                    )
                
                raise
        
        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            start_time = time.time()
            
            try:
                result = func(*args, **kwargs)
                execution_time = time.time() - start_time
                
                if metric_type == "api":
                    performance_monitor.record_api_metric(
                        endpoint=func.__name__,
                        method="SYNC",
                        response_time=execution_time,
                        status_code=200
                    )
                
                return result
                
            except Exception as e:
                execution_time = time.time() - start_time
                
                if metric_type == "api":
                    performance_monitor.record_api_metric(
                        endpoint=func.__name__,
                        method="SYNC",
                        response_time=execution_time,
                        status_code=500
                    )
                
                raise
        
        return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
    return decorator


class DatabaseProfiler:
    """数据库查询分析器"""
    
    def __init__(self):
        self.query_log = deque(maxlen=1000)
    
    def profile_query(self, query: str, params: Any = None):
        """分析数据库查询性能"""
        def decorator(func: Callable) -> Callable:
            @wraps(func)
            async def wrapper(*args, **kwargs):
                start_time = time.time()
                
                try:
                    result = await func(*args, **kwargs)
                    execution_time = time.time() - start_time
                    
                    # 记录查询信息
                    query_info = {
                        'query': query[:200] + "..." if len(query) > 200 else query,
                        'execution_time': execution_time,
                        'timestamp': datetime.utcnow(),
                        'success': True,
                        'params': str(params)[:100] if params else None,
                    }
                    
                    self.query_log.append(query_info)
                    performance_monitor.record_db_metric("custom", execution_time)
                    
                    return result
                    
                except Exception as e:
                    execution_time = time.time() - start_time
                    
                    query_info = {
                        'query': query[:200] + "..." if len(query) > 200 else query,
                        'execution_time': execution_time,
                        'timestamp': datetime.utcnow(),
                        'success': False,
                        'error': str(e),
                        'params': str(params)[:100] if params else None,
                    }
                    
                    self.query_log.append(query_info)
                    raise
                    
            return wrapper
        return decorator
    
    def get_slow_queries(self, threshold: float = 1.0) -> List[Dict[str, Any]]:
        """获取慢查询"""
        return [q for q in self.query_log if q['execution_time'] > threshold]
    
    def analyze_queries(self) -> Dict[str, Any]:
        """分析查询模式"""
        if not self.query_log:
            return {"no_data": True}
        
        execution_times = [q['execution_time'] for q in self.query_log]
        successful_queries = [q for q in self.query_log if q['success']]
        failed_queries = [q for q in self.query_log if not q['success']]
        
        return {
            "total_queries": len(self.query_log),
            "avg_execution_time": statistics.mean(execution_times),
            "max_execution_time": max(execution_times),
            "success_rate": len(successful_queries) / len(self.query_log) * 100,
            "slow_queries_count": len(self.get_slow_queries()),
            "recent_errors": [q['error'] for q in failed_queries[-5:]],
        }


# 全局数据库分析器实例
db_profiler = DatabaseProfiler()


async def start_performance_monitoring():
    """启动性能监控后台任务"""
    async def monitoring_task():
        while True:
            try:
                performance_monitor.record_system_metric()
                await asyncio.sleep(60)  # 每分钟记录一次系统指标
            except Exception as e:
                logger.error(f"性能监控任务错误: {e}")
                await asyncio.sleep(60)
    
    # 启动后台监控任务
    asyncio.create_task(monitoring_task())
    logger.info("性能监控已启动")


class MemoryProfiler:
    """内存使用分析器"""
    
    @staticmethod
    def get_memory_usage() -> Dict[str, Any]:
        """获取当前内存使用情况"""
        try:
            process = psutil.Process()
            memory_info = process.memory_info()
            memory_percent = process.memory_percent()
            
            # 系统内存信息
            system_memory = psutil.virtual_memory()
            
            return {
                "process_memory": {
                    "rss": memory_info.rss,
                    "vms": memory_info.vms,
                    "percent": memory_percent,
                },
                "system_memory": {
                    "total": system_memory.total,
                    "available": system_memory.available,
                    "percent": system_memory.percent,
                    "used": system_memory.used,
                    "free": system_memory.free,
                }
            }
        except Exception as e:
            logger.error(f"内存信息获取失败: {e}")
            return {"error": str(e)}
    
    @staticmethod
    def memory_alert_check():
        """内存使用告警检查"""
        try:
            memory_usage = MemoryProfiler.get_memory_usage()
            
            if memory_usage.get("system_memory", {}).get("percent", 0) > 90:
                logger.critical("系统内存使用率超过90%")
                return True
            
            if memory_usage.get("process_memory", {}).get("percent", 0) > 50:
                logger.warning("进程内存使用率超过50%")
                return True
                
            return False
            
        except Exception as e:
            logger.error(f"内存告警检查失败: {e}")
            return False


def optimize_query_suggestion(query_time: float, query_type: str) -> List[str]:
    """根据查询性能提供优化建议"""
    suggestions = []
    
    if query_time > 2.0:
        suggestions.append("考虑添加适当的数据库索引")
        suggestions.append("检查查询条件是否可以优化")
        
    if query_type.lower() in ["select", "search"]:
        suggestions.append("考虑使用分页限制结果集大小")
        suggestions.append("检查是否可以使用缓存")
        
    if query_time > 5.0:
        suggestions.append("考虑将复杂查询拆分为多个简单查询")
        suggestions.append("检查数据库连接池配置")
        suggestions.append("考虑使用异步查询")
        
    return suggestions